﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using GMap.NET;
using GMap.NET.EXT;
using GMap.NET.EXT.providers;
using GMap.NET.WindowsForms;
using GMap.NET.WindowsForms.Markers;
using LeakView.common;
using LeakView.service;
using log4net;

namespace LeakView.view
{
    public partial class ViewMap : UserControl, Splashable
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(ViewMap));

        StartEndOverlay startEndOverlay = new StartEndOverlay();

        RouteOverlay routeOverlay = new RouteOverlay();

        LeaksOverlay leaksOverlay = new LeaksOverlay();

        private Action<AjaxLeakInfo> leakComfirmAction = null;

        public Action<AjaxLeakInfo> LeakComfirmAction { get => leakComfirmAction; set => leakComfirmAction = value; }

        public ViewMap()
        {
            InitializeComponent();
        }

        private void ViewMap_Load(object sender, EventArgs e)
        {
            this.label_location.Parent = this.gMapControl1;
            this.label_zoom.Parent = this.gMapControl1;
            this.button_center.Parent = this.gMapControl1;

            MainModule.current.LeakCreatedHandler += new Action<AjaxLeakInfo>(this.createLeak);
            MainModule.current.LeakDeletedHandler += new Action<AjaxLeakInfo>(this.deleteLeak);

            //Bing混合地图  
            GMapControl gMap = this.gMapControl1;
            if(!CSharpUtilities.IsDesignMode())
            {
                gMap.MapProvider = AMapProvider.Instance;
                gMap.CacheLocation = Application.StartupPath + "\\maps";
            }

            //访问模式
            int mode = AnyConfigs.get("APP").get("MapAccessMode").GetOrDefault(1);
            switch(mode)
            {
                case 0:
                    gMap.Manager.Mode = AccessMode.ServerOnly;
                    break;
                case 2:
                    gMap.Manager.Mode = AccessMode.CacheOnly;
                    break;
                default:
                    gMap.Manager.Mode = AccessMode.ServerAndCache;
                    break;
            }

            //不显示中心十字点  
            gMap.ShowCenter = false;

            //左键拖拽地图  
            gMap.DragButton = MouseButtons.Left;
            gMap.MinZoom = 1;   //最小缩放  
            gMap.MaxZoom = 18;  //最大缩放  

            gMap.Overlays.Add(routeOverlay);
            gMap.Overlays.Add(startEndOverlay);
            gMap.Overlays.Add(leaksOverlay);

            gMap.Zoom = Properties.Settings.Default.map_zoom;

            //地图中心位置  
            gMap.Position = PipeModal.default_center;  //中心点的纬度，经度   

            MainModule.current.GetCurrentLeaks().ForEach(n =>
            {
                createLeak(n);
            });

        }

        public void createLeak(AjaxLeakInfo leak)
        {
            leaksOverlay.insertLeak(leak);
        }

        public void deleteLeak(AjaxLeakInfo leak)
        {
            try
            {
                leaksOverlay.removeLeak(leak);
            }
            catch(Exception e)
            {
                log.Warn("Remove leak exception.", e);
            }
        }


        public void splash(bool flag)
        {
            int zoom = (int)this.gMapControl1.Zoom;
            if (zoom != Properties.Settings.Default.map_zoom)
            {
                Properties.Settings.Default.map_zoom = zoom;
                Properties.Settings.Default.Save();
            }


            this.routeOverlay.splash(flag);

            this.startEndOverlay.splash(flag);

            this.leaksOverlay.splash(flag);

            this.gMapControl1.Refresh();

        }

        public void dispatchDownload()
        {
            AccessMode oldMode = this.gMapControl1.Manager.Mode;
            this.gMapControl1.Manager.Mode = AccessMode.ServerAndCache;

            try
            {
                Console.WriteLine(this.gMapControl1.ViewArea.ToString());

                int zoom_min = this.gMapControl1.MinZoom;

                ZoomFetchers fetchers = new ZoomFetchers();

                for (int i = this.gMapControl1.MinZoom; i < this.gMapControl1.MaxZoom; i++)
                {

                    this.gMapControl1.Zoom = i;
                    this.gMapControl1.Position = PipeModal.ME.Center;
                    fetchers[i].Area = this.gMapControl1.ViewArea;
                }

                fetchers.fetch(this.gMapControl1.MapProvider);

            }
            finally
            {
                this.gMapControl1.Manager.Mode = oldMode;
                this.gMapControl1.Refresh();
            }
        }

        public void dispatchUpdateServer()
        {
            this.gMapControl1.Position = PipeModal.ME.Center;
            this.routeOverlay.reset();
        }

        private void button_center_Click(object sender, EventArgs e)
        {
            gMapControl1.Position = PipeModal.ME.Center;
        }

        private void gMapControl1_OnMapZoomChanged()
        {
            this.label_zoom.Text = "层级:" + this.gMapControl1.Zoom.ToString();
        }

        private void gMapControl1_MouseMove(object sender, MouseEventArgs e)
        {
            PointLatLng pnew = gMapControl1.FromLocalToLatLng(e.X, e.Y);
            this.label_location.Text = "坐标:" + pnew.Lng.ToString() + "," + pnew.Lat.ToString();
        }

        private void gMapControl1_OnMarkerClick(GMapMarker item, MouseEventArgs e)
        {
            if (item.Tag != null)
            {
                try
                {
                    AjaxLeakInfo leakInfo = (AjaxLeakInfo)item.Tag;

                    leakComfirmAction?.Invoke(leakInfo);
                }
                catch(Exception ex)
                {
                    log.Error("Exception on gmap confirm leak.", ex);
                }

            }
        }


        class RouteOverlay : GMapOverlay, Splashable
        {
            private GMapRoute route = null;

            public void splash(bool flag)
            {
                if (PipeModal.ME.Valid)
                {
                    show();
                }
                else
                {
                    hide();
                }
            }

            public void reset()
            {
                hide();
                show();
            }

            public void show()
            {
                if (this.route == null)
                {
                    route = new GMapRoute(PipeModal.ME.Points, "line")
                    {
                        Stroke = new Pen(Color.Chocolate, 4.0F)
                    };
                    this.Routes.Add(route);

                    this.Control.Position = PipeModal.ME.Center;

                }
            }

            public void hide()
            {
                if (this.route != null)
                {
                    this.Routes.Clear();
                    this.route = null;
                }
            }
        }

        class StartEndOverlay : GMapOverlay, Splashable
        {
            GMapMarker start = new GMarkerGoogle(PipeModal.default_center, GMarkerGoogleType.green_dot);
            GMapMarker startSplash = new GMarkerGoogle(PipeModal.default_center, GMarkerGoogleType.red_dot);
            GMapMarker end = new GMarkerGoogle(PipeModal.default_center, GMarkerGoogleType.blue_dot);
            GMapMarker endSplash = new GMarkerGoogle(PipeModal.default_center, GMarkerGoogleType.red_dot);

            private bool startStatus = false;
            private bool endStatus = false;

            public StartEndOverlay()
            {
                start.ToolTipText = "起点";
                start.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                start.IsVisible = false;
                Markers.Add(start);

                startSplash.ToolTipText = "起点";
                startSplash.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                startSplash.IsVisible = false;
                Markers.Add(startSplash);

                end.ToolTipText = "终点";
                end.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                end.IsVisible = false;
                Markers.Add(end);

                endSplash.ToolTipText = "终点";
                endSplash.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                endSplash.IsVisible = false;
                Markers.Add(endSplash);

            }

            public void splash(bool flag)
            {
                if (PipeModal.ME.Valid)
                {
                    show(flag);
                }
                else
                {
                    hide();
                }

                if (MainModule.pair.Value.Valid)
                {
                    start.ToolTipText = MainModule.pair.Value.Value.head.name;
                    startSplash.ToolTipText = MainModule.pair.Value.Value.head.name;
                    end.ToolTipText = MainModule.pair.Value.Value.tail.name;
                    endSplash.ToolTipText = MainModule.pair.Value.Value.tail.name;
                }
                else
                {
                    start.ToolTipText = "起点";
                    startSplash.ToolTipText = "起点";
                    end.ToolTipText = "终点";
                    endSplash.ToolTipText = "终点";
                }
            }

            public bool Alarm
            {
                get { return !MainModule.current.Value.Valid || !startStatus || !endStatus; }
            }

            public void show(bool splash)
            {
                start.Position = PipeModal.ME.First;
                startSplash.Position = PipeModal.ME.First;

                end.Position = PipeModal.ME.Last;
                endSplash.Position = PipeModal.ME.Last;

                if (MainModule.status.Value.Valid)
                {
                    AjaxLeakPairStatus status = MainModule.status.Value.Value;

                    // start
                    if (!status.head)
                    {
                        start.IsVisible = !splash;
                        startSplash.IsVisible = splash;
                        startStatus = false;
                    }
                    else
                    {
                        startSplash.IsVisible = false;
                        start.IsVisible = true;
                        startStatus = true;
                    }

                    // end
                    if (!status.tail)
                    {
                        end.IsVisible = !splash;
                        endSplash.IsVisible = splash;
                        endStatus = false;
                    }
                    else
                    {
                        endSplash.IsVisible = false;
                        end.IsVisible = true;
                        endStatus = true;
                    }

                }
                else
                {
                    endSplash.IsVisible = false;
                    end.IsVisible = true;
                    startSplash.IsVisible = false;
                    start.IsVisible = true;
                }

            }

            public void hide()
            {
                start.IsVisible = false;
                startSplash.IsVisible = false;
                end.IsVisible = false;
                endSplash.IsVisible = false;
            }
        }
        class LeaksOverlay : GMapOverlay, Splashable
        {
            Dictionary<long, GMapMarker> leaks = new Dictionary<long, GMapMarker>();

            List<AjaxLeakInfo> waitToInsert = new List<AjaxLeakInfo>();

            public LeaksOverlay()
            {
            }

            public void splash(bool flag)
            {
                waitToInsert.ForEach(n =>
                {
                    innerInsertLeak(n);
                });
                waitToInsert.Clear();

                if (PipeModal.ME.Valid && MainModule.current.Value.Valid)
                {
                    show();
                }
                else
                {
                    hide();
                }
            }

            public void insertLeak(AjaxLeakInfo leak)
            {
                waitToInsert.Add(leak);
            }

            public void innerInsertLeak(AjaxLeakInfo leak)
            {
                if (this.leaks.ContainsKey(leak.id))
                    return;

                PointLatLng pos = PipeModal.ME.GetPosition(leak.location);
                GMapMarker leakMarker = new GMarkerGoogle(pos, GMarkerGoogleType.red_pushpin)
                {
                    ToolTipText = leak.location.ToString("F3") + "千米",
                    ToolTipMode = MarkerTooltipMode.OnMouseOver,
                    Tag = leak
                };
                this.Markers.Add(leakMarker);

                this.leaks.Add(leak.id, leakMarker);

                //this.Control?.Refresh();

            }

            public void removeLeak(AjaxLeakInfo leak)
            {
                if (leak != null)
                {
                    this.Markers.Remove(leaks[leak.id]);
                    leaks.Remove(leak.id);
                    //this.Control?.Refresh();
                }
            }

            public void show()
            {
                this.IsVisibile = true;
            }

            public void hide()
            {
                this.IsVisibile = false;
            }

        }


    }




}
